﻿using Microsoft.Extensions.Configuration;
using ServiceStack.OrmLite;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Text;

namespace OrmLite_Test
{
    public class DBLogic
    {
        static DBLogic()
        {
            //执行超时
            OrmLiteConfig.CommandTimeout = 60 * 10;
            OrmLiteConfig.DialectProvider = SqlServer2016Dialect.Provider;
        }

        private static IConfigurationRoot _ConfigurationRoot = null;
        public static IConfigurationRoot ConfigurationRoot
        {
            get
            {
                if (_ConfigurationRoot == null)
                {
                    _ConfigurationRoot = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
                            .AddJsonFile("app.json", true, true)
                            .Build();
                }
                return _ConfigurationRoot;
            }
        }

        private static string _ConnectionString = null;
        public static string ConnectionString
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_ConnectionString))
                {
                    _ConnectionString = ConfigurationRoot["SqlServer"];
                }
                return _ConnectionString;
            }
        }

        public static IDbConnection OpenConn(string connString = null, IOrmLiteDialectProvider dialectProvider = null)
        {
            dialectProvider = dialectProvider ?? OrmLiteConfig.DialectProvider;

            connString = connString ?? ConnectionString;

            dialectProvider.GetStringConverter().UseUnicode = true;

            return new OrmLiteConnectionFactory(connString, dialectProvider).OpenDbConnection();
        }


        /// <summary>
        /// bool has42YearOlds = db.Exists<Person>(new { Age = 42 });
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static bool Exists<T>(Expression<Func<T, bool>> expression)
        {
            using (var db = OpenConn())
            {
                return db.Exists<T>(expression);
            }
        }

        public static bool Exists<T>(object anonType = null)
        {
            using (var db = OpenConn())
            {
                return db.Exists<T>(anonType);
            }
        }

        public static List<T> SelectAll<T>()
        {
            using (var db = OpenConn())
            {
                return db.Select<T>();
            }
        }


        public static List<T> Select<T>(Expression<Func<T, bool>> predicate)
        {
            using (var db = OpenConn())
            {
                var q = db.From<T>().Where(predicate);

                return db.Select(q);
            }
        }

        public static List<T> Select<T>(string sql, object anonType = null)
        {
            using (var db = OpenConn())
            {
                return db.Select<T>(sql, anonType);
            }
        }

        public static List<T> SelectByIds<T>(IEnumerable idValues)
        {
            using (var db = OpenConn())
            {
                return db.SelectByIds<T>(idValues);
            }
        }

        public static T SingleById<T>(object idValue)
        {
            using (var db = OpenConn())
            {
                return db.SingleById<T>(idValue);
            }
        }

        public static T Single<T>(Expression<Func<T, bool>> expression)
        {
            using (var db = OpenConn())
            {
                return db.Single<T>(expression);
            }
        }

        public static T SingleWhere<T>(string name, object idValue)
        {
            using (var db = OpenConn())
            {
                return db.SingleWhere<T>(name, idValue);
            }
        }


        public static long Count<T>(Expression<Func<T, bool>> expression)
        {
            using (var db = OpenConn())
            {
                return db.Count(expression);
            }
        }

        /// <summary>
        /// int maxAgeUnder50 = db.Scalar<Person, int>(x => Sql.Max(x.Age), x => x.Age < 50);
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="field"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static TKey Scalar<T, TKey>(Expression<Func<T, object>> field, Expression<Func<T, bool>> predicate)
        {
            using (var db = OpenConn())
            {
                return db.Scalar<T, TKey>(field, predicate);
            }
        }


        public static long Insert<T>(T entity)
        {
            using (var db = OpenConn())
            {
                return db.Insert(entity, selectIdentity: true);
            }
        }

        public static void Insert<T>(params T[] entitys)
        {
            using (var db = OpenConn())
            {
                db.Insert<T>(entitys);
            }
        }


        public static bool Save<T>(T entity)
        {
            using (var db = OpenConn())
            {
                return db.Save<T>(entity);
            }
        }

        public static int Delete<T>(Expression<Func<T, bool>> where)
        {
            using (var db = OpenConn())
            {
                return db.Delete<T>(where);
            }
        }

        public static int DeleteById<T>(object id)
        {
            using (var db = OpenConn())
            {
                return db.DeleteById<T>(id);
            }
        }

        public static int DeleteByIds<T>(IEnumerable idValues)
        {
            using (var db = OpenConn())
            {
                return db.DeleteByIds<T>(idValues);
            }
        }

        public static int Update<T>(T entity)
        {
            using (var db = OpenConn())
            {
                return db.Update<T>(entity);
            }
        }


        public static int Update<T>(object updateOnly, Expression<Func<T, bool>> where)
        {
            using (var db = OpenConn())
            {
                return db.Update<T>(updateOnly, where);
            }
        }

        public static int UpdateAll<T>(IEnumerable<T> objs)
        {
            using (var db = OpenConn())
            {
                return db.UpdateAll<T>(objs);
            }
        }

        public static bool Upsert<T>(T entity)
        {
            return Save<T>(entity);
        }

        public static List<Ret> Column<T, Ret>(Expression<Func<T, object>> fieldExpr, Expression<Func<T, bool>> predicate)
        {
            using (var db = OpenConn())
            {
                var q = db.From<T>().Select(fieldExpr).Where(predicate);
                return db.Column<Ret>(q);
            }
        }
    }
}
